package cn.lingyangwl.agile.system.controller;

import cn.hutool.core.codec.Base64;
import cn.lingyangwl.agile.common.core.config.GlobalProperties;
import cn.lingyangwl.agile.model.constants.*;
import cn.lingyangwl.agile.model.enums.ConfigKeyEnum;
import cn.lingyangwl.agile.model.module.config.param.BaseConfigParam;
import cn.lingyangwl.agile.system.manager.SysConfigManager;
import cn.lingyangwl.agile.system.mapper.SysConfigMapper;
import cn.lingyangwl.agile.system.model.entity.SysConfig;
import cn.lingyangwl.agile.tenant.core.utils.TenantUtils;
import cn.lingyangwl.framework.core.response.Resp;
import cn.lingyangwl.framework.tool.core.StringUtils;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import cn.lingyangwl.framework.tool.crypto.AesCrypto;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author shenguangyang
 */
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/test")
public class TestController {
    private static final Map<String, Function<TestReq, Object>> map = new HashMap<>();

    private final GlobalProperties globalProperties;
    private final SysConfigMapper configMapper;
    private final SysConfigManager configManager;

    public static class TestReq {
        @Getter
        @Setter
        private String type;
        @Getter
        @Setter
        private JSONObject data;
    }

    @PostConstruct
    public void init() {
        map.put("configDecrypt", this::configDecrypt);
        map.put("cleanConfigData", this::cleanConfigData);
        map.put("recoverConfigData", this::recoverConfigData);
        map.put("processConfigSensitiveData", this::processConfigSensitiveData);
    }

    @PostMapping("/do")
    public Resp<Object> postRequest(@RequestBody TestReq req) {
        if (!map.containsKey(req.getType())) {
            Set<String> keys = map.keySet();
            return Resp.fail(-1,"不存在 " + req.type, keys);
        }
        return Resp.ok(map.get(req.getType()).apply(req));
    }

    public Map<String, Object> configDecrypt(TestReq req) {
        TenantUtils.executeIgnore(DataIsolateLevel.ALL, () -> {
            List<SysConfig> configList = configMapper.selectList(SysConfig.lqw());
            AesCrypto aesCrypto = new AesCrypto(globalProperties.getSecretKey());
            configList.stream()
                    .filter(e -> StringUtils.isNotEmpty(e.getConfigValue()))
                    .forEach(e -> {
                        try {
                            e.setConfigValue(aesCrypto.decrypt(Base64.encode(e.getConfigValue())));
                        } catch (Exception e1) {
                            log.error("error: {}, configKey: {}, configValue: {}", e1.getMessage(), e.getConfigKey(), e.getConfigValue());
                            throw new BizException(e1.getMessage());
                        }
                    });
            configList.forEach(configMapper::updateById);
        });
        return Collections.emptyMap();
    }


    private static List<SysConfig> bkConfig = new ArrayList<>();
    public Map<String, Object> cleanConfigData(TestReq req) {
        TenantUtils.executeIgnore(DataIsolateLevel.ALL, () -> {
            List<SysConfig> configList = configMapper.selectList(SysConfig.lqw());
            bkConfig = configList.stream().map(e -> {
                SysConfig config = new SysConfig();
                BeanUtils.copyProperties(e, config);
                return config;
            }).collect(Collectors.toList());

            for (SysConfig config : configList) {
                try {
                    JSONObject parse = JSONObject.parse(config.getConfigValue());
                    if (Objects.isNull(parse)) {
                        continue;
                    }
                    parse.keySet().forEach(key -> parse.put(key, "demo"));
                    config.setConfigValue(JSON.toJSONString(parse));
                    configMapper.updateById(config);
                } catch (Exception e) {
                    log.error("error: {}", e.getMessage());
                }
            }
        });
        return Collections.emptyMap();
    }

    public Map<String, Object> recoverConfigData(TestReq req) {
        TenantUtils.executeIgnore(DataIsolateLevel.ALL, () -> {
            bkConfig.forEach(configMapper::updateById);
        });
        return Collections.emptyMap();
    }

    public Object processConfigSensitiveData(TestReq req) {
        SysConfig config = configManager.getByConfigKey(ConfigKeyEnum.WX_MP.getKey());
        ConfigKeyEnum configKeyEnum = ConfigKeyEnum.of(config.getConfigKey());
        String configValue = BaseConfigParam.processSensitiveData(configKeyEnum, config.getConfigValue());
        return JSONObject.parseObject(configValue);
    }
}
